#pragma once

#include <AVUIAnimatable.h>

namespace AVUI {

class Transform;

class GeneralTransform : public Animatable
{
public:
    DECLARE_ELEMENT(GeneralTransform, Animatable);

#pragma region Public Methods

    /// <summary>Creates a modifiable clone of this <see cref="T:System.Windows.Media.GeneralTransform" />, making deep copies of this object's values. When copying dependency properties, this method copies resource references and data bindings (but they might no longer resolve) but not animations or their current values.</summary>
    /// <returns>A modifiable clone of the current object. The cloned object's <see cref="P:System.Windows.Freezable.IsFrozen" /> property will be false even if the source's <see cref="P:System.Windows.Freezable.IsFrozen" /> property was true.</returns>
    TRefCountedPtr<GeneralTransform> Clone() { return (GeneralTransform*) Animatable::Clone().get_Ptr(); }

    /// <summary>Creates a modifiable clone of this <see cref="T:System.Windows.Media.GeneralTransform" /> object, making deep copies of this object's current values. Resource references, data bindings, and animations are not copied, but their current values are. </summary>
    /// <returns>A modifiable clone of the current object. The cloned object's <see cref="P:System.Windows.Freezable.IsFrozen" /> property will be false even if the source's <see cref="P:System.Windows.Freezable.IsFrozen" /> property was true.</returns>
    TRefCountedPtr<GeneralTransform> CloneCurrentValue() { return (GeneralTransform*) Animatable::CloneCurrentValue().get_Ptr(); }

    /// <summary>Transforms the specified point and returns the result.</summary>
    /// <returns>The result of transforming <paramref name="point" />.</returns>
    /// <param name="point">The point to transform.</param>
    /// <exception cref="T:System.InvalidOperationException">The transform did not succeed.</exception>
    Point Transform(const Point& point)
    {
        Point point2;
        if (!TryTransform(point, &point2))
        {
            LibraryThrowException(object_allocate<InvalidOperationException>("Transform failed."));
        }
        return point2;
    }

    /// <summary>When overridden in a derived class, transforms the specified bounding box and returns an axis-aligned bounding box that is exactly large enough to contain it.</summary>
    /// <returns>The smallest axis-aligned bounding box possible that contains the transformed <paramref name="rect" />.</returns>
    /// <param name="rect">The bounding box to transform.</param>
    virtual Rect TransformBounds(Rect rect) = 0;
 
    /// <summary>When overridden in a derived class, attempts to transform the specified point and returns a value that indicates whether the transformation was successful.</summary>
    /// <returns>true if <paramref name="inPoint" /> was transformed; otherwise, false.</returns>
    /// <param name="inPoint">The point to transform.</param>
    /// <param name="result">The result of transforming <paramref name="inPoint" />.</param>
    virtual bool TryTransform(const Point& inPoint, Point* pResult) = 0;

#pragma endregion Public Methods

#pragma region Public Properties

    /// <summary>Gets the inverse transformation of this <see cref="T:System.Windows.Media.GeneralTransform" />, if possible.</summary>
    /// <returns>An inverse of this instance, if possible; otherwise null.</returns>
    virtual TRefCountedPtr<GeneralTransform> get_Inverse() = 0;

#pragma endregion Public Properties

#pragma region Internal Properties

    virtual TRefCountedPtr<AVUI::Transform> get_AffineTransform() { return NULL; }

#pragma endregion Internal Properties

};


}; // namespace AVUI
